package com.zsc.common.web.thread;

import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;

import com.zsc.common.web.handler.ServiceHandler;
import com.zsc.common.web.util.Constant;
import org.apache.log4j.Logger;

/**
 * TimerThread.java是互动平台的定时业务事务运行线程类。
 *
 * @author jason
 * @version 1.0 2017年3月19日
 */
public class TimerThread extends Thread {

    /**
     * 日志器
     */
    private static final Logger logger = Logger.getLogger(TimerThread.class);

    /**
     * 定时事务处理器
     */
    private Timer timer = new Timer();

    /**
     * 默认5秒时间，单位是毫秒。
     */
    private static long defaultTime = 5000;

    /**
     * 执行事务前的延迟时间，单位是毫秒。
     */
    private long delay;

    /**
     * 执行各后续事务之间的时间间隔，单位是毫秒。
     */
    private long period;

    /**
     * 第一个定时事务的开始时刻的小时点。
     */
    private int hour;

    /**
     * 第一个定时事务的开始时刻的分钟点。
     */
    private int minute;

    /**
     * 第一个定时事务的开始时刻的秒点。
     */
    private int second;

    /**
     * 定时业务事务处理器
     */
    private ServiceHandler serviceHandler = null;

    /**
     * 定时业务事务
     */
    private ServiceTimerTask serviceTimerTask = null;

    /**
     * 首次执行时间点
     */
    private Calendar firstTime = null;

    /**
     * 以默认5秒延迟时间开始执行和默认5秒周期的构造函数。
     *
     * @param serviceHandler 定时业务事务处理器
     */
    public TimerThread(ServiceHandler serviceHandler) {
        this(0, 0, 0, defaultTime, defaultTime, serviceHandler);
    }

    /**
     * 以默认5秒延迟时间开始执行的构造函数。
     *
     * @param period         执行各后续事务之间的时间间隔，单位是毫秒。
     * @param serviceHandler 定时业务事务处理器
     */
    public TimerThread(long period, ServiceHandler serviceHandler) {
        this(0, 0, 0, defaultTime, period, serviceHandler);
    }

    /**
     * 可设置延迟时间和时间间隔的构造函数。
     *
     * @param delay          执行事务前的延迟时间，单位是毫秒。
     * @param period         执行各后续事务之间的时间间隔，单位是毫秒。
     * @param serviceHandler 定时业务事务处理器
     */
    public TimerThread(long delay, long period, ServiceHandler serviceHandler) {
        this(0, 0, 0, delay, period, serviceHandler);
    }

    /**
     * 构造函数。
     *
     * @param hour           第一个定时事务的开始时刻的小时点。
     * @param minute         第一个定时事务的开始时刻的分钟点。
     * @param second         第一个定时事务的开始时刻的秒点。
     * @param delay          执行事务前的延迟时间，单位是毫秒。
     * @param period         执行各后续事务之间的时间间隔，单位是毫秒。
     * @param serviceHandler 定时业务事务处理器
     */
    public TimerThread(int hour, int minute, int second, long delay, long period, ServiceHandler serviceHandler) {
        super("定时业务事务");
        this.hour = hour;
        this.minute = minute;
        this.second = second;
        this.delay = delay;
        this.period = period;
        this.serviceHandler = serviceHandler;
        this.serviceTimerTask = new ServiceTimerTask();
        firstTime = Calendar.getInstance();
        firstTime.set(Calendar.HOUR_OF_DAY, hour);
        firstTime.set(Calendar.MINUTE, minute);
        firstTime.set(Calendar.SECOND, second);
    }

    /*
     * (non-Javadoc)
     *
     * @see java.lang.Thread#run()
     */
    @Override
    public void run() {
        doWork();
    }

    /**
     * 执行定时业务事务。
     */
    public void doWork() {
        // 如果时间间隔大于0，则表示周期性定时业务事务；反之，则表示一次性定时业务事务。
        if (period > 0) {
            // 如果时刻、分钟或秒的值不等于0，则表示不需要延迟执行。
            if (hour != 0 || minute != 0 || second != 0) {
                // 取得当前时间点
                Calendar currentTime = Calendar.getInstance();
                // 如果当前时间点在当前定时业务事务的首次执行时间点之前，那么按照当天的其首次执行时间点进行执行。
                if (currentTime.before(firstTime)) {
                    timer.schedule(serviceTimerTask, firstTime.getTime(), period);
                } else {
                    // 反之，那么 延迟到第二天的首次执行时间点进行执行。
                    delay = (Constant.DATE_24_TIME_MILLISECOND + firstTime.getTimeInMillis()) - currentTime.getTimeInMillis();
                    timer.schedule(serviceTimerTask, delay, period);
                }
            } else if (delay > 0) {
                timer.schedule(serviceTimerTask, delay, period);
            }
        } else {
            // 在指定时间点执行一次定时业务事务。
            timer.schedule(serviceTimerTask, firstTime.getTime());
        }
    }

    /**
     * 终止此计时器线程，丢弃所有当前已安排的事务。
     */
    public void cancel() {
        timer.cancel();
        timer = null;
        serviceHandler = null;
        serviceTimerTask = null;
    }

    /**
     * @return the delay
     */
    public long getDelay() {
        return delay;
    }

    /**
     * @param delay the delay to set
     */
    public void setDelay(long delay) {
        this.delay = delay;
    }

    /**
     * @return the period
     */
    public long getPeriod() {
        return period;
    }

    /**
     * @param period the period to set
     */
    public void setPeriod(long period) {
        this.period = period;
    }

    /**
     * @return the hour
     */
    public int getHour() {
        return hour;
    }

    /**
     * @param hour the hour to set
     */
    public void setHour(int hour) {
        this.hour = hour;
    }

    /**
     * @return the minute
     */
    public int getMinute() {
        return minute;
    }

    /**
     * @param minute the minute to set
     */
    public void setMinute(int minute) {
        this.minute = minute;
    }

    /**
     * @return the second
     */
    public int getSecond() {
        return second;
    }

    /**
     * @param second the second to set
     */
    public void setSecond(int second) {
        this.second = second;
    }

    /**
     * @param serviceHandler the serviceHandler to set
     */
    public void setServiceHandler(ServiceHandler serviceHandler) {
        this.serviceHandler = serviceHandler;
    }

    /**
     * @param timer the timer to set
     */
    public void setTimer(Timer timer) {
        this.timer = timer;
    }

    /**
     * @param serviceTimerTask the serviceTimerTask to set
     */
    public void setServiceTimerTask(ServiceTimerTask serviceTimerTask) {
        this.serviceTimerTask = serviceTimerTask;
    }

    /**
     * @param firstTime the firstTime to set
     */
    public void setFirstTime(Calendar firstTime) {
        this.firstTime = firstTime;
    }

    /**
     * ServiceTimerTask.java是互动平台的定时业务事务类。
     *
     * @author jason
     * @version 1.0 2017年3月19日
     */
    protected class ServiceTimerTask extends TimerTask {

        /*
         * (non-Javadoc)
         *
         * @see java.util.TimerTask#run()
         */
        @Override
        public void run() {
            logger.debug("开始处理" + serviceHandler.name() + "定时业务事务。");
            try {
                serviceHandler.service();
            } catch (Throwable e) {
                logger.error("运行处理" + serviceHandler.name() + "定时业务事务的时候发生异常！", e);
            }
            logger.debug("结束处理" + serviceHandler.name() + "定时业务事务。");
        }
    }
}
